package cmd

import (
	"context"
	"fmt"
	"golang.org/x/text/encoding/simplifiedchinese"
	"golang.org/x/text/transform"
	"io"
	"os/exec"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"
)

type ProcessInfo struct {
	PID  int
	Port int
	Name string
}

func KillProcessByPID(pid int) error {
	var cmd *exec.Cmd
	switch runtime.GOOS {
	case "windows":
		cmd = exec.Command("taskkill", "/F", "/PID", strconv.Itoa(pid))
	case "linux", "darwin":
		cmd = exec.Command("kill", "-9", strconv.Itoa(pid))
	default:
		return fmt.Errorf("unsupported platform: %s", runtime.GOOS)
	}
	output, err := cmd.CombinedOutput()
	if err != nil {
		return fmt.Errorf("failed to kill process %d: %v, output: %s", pid, err, GbkToUTF8(output))
	}
	fmt.Printf("Successfully killed process with PID: %d\n", pid)
	return nil
}

func GbkToUTF8(data []byte) string {
	reader := transform.NewReader(strings.NewReader(string(data)), simplifiedchinese.GBK.NewDecoder())
	utf8Data, err := io.ReadAll(reader)
	if err != nil {
		return "none"
	}
	return string(utf8Data)
}

func KillProcessByPort(port int) error {
	var cmd *exec.Cmd
	switch runtime.GOOS {
	case "windows":
		cmd = exec.Command("cmd", "/c", fmt.Sprintf("netstat -ano | findstr :%d", port))
	case "linux", "darwin":
		cmd = exec.Command("lsof", "-i", fmt.Sprintf(":%d", port), "-t")
	default:
		return fmt.Errorf("unsupported platform: %s", runtime.GOOS)
	}
	output, err := cmd.Output()
	if err != nil {
		return fmt.Errorf("failed to find process on port %d: %v", port, err)
	}
	if len(output) == 0 {
		return fmt.Errorf("no process found on port %d", port)
	}
	var processIds []int
	if runtime.GOOS == "windows" {
		lines := strings.Split(string(output), "\n")
		for _, line := range lines {
			fields := strings.Fields(line)
			if len(fields) >= 5 {
				pidStr := fields[len(fields)-1]
				if pid, err := strconv.Atoi(pidStr); err == nil {
					processIds = append(processIds, pid)
				}
			}
		}
	} else {
		pidStr := strings.TrimSpace(string(output))
		if pid, err := strconv.Atoi(pidStr); err == nil {
			processIds = append(processIds, pid)
		}
	}

	if len(processIds) == 0 {
		return fmt.Errorf("no valid PID found for port %d", port)
	}
	removeDuplicateIds := removeDuplicates(processIds)
	for _, pid := range removeDuplicateIds {
		if err := KillProcessByPID(pid); err != nil {
			return err
		}
	}
	return nil
}

func KillProcessByPath(port string) error {

	return nil
}

func removeDuplicates(processIds []int) []int {
	seen := make(map[int]bool)
	var result []int

	for _, pid := range processIds {
		if !seen[pid] {
			seen[pid] = true
			result = append(result, pid)
		}
	}
	return result
}

func StartProcess(path string) error {
	output, err := ExecuteScript(path, 3*time.Second)
	if err != nil {
		return err
	}
	fmt.Printf("Successfully execute path: %s result: %s\n", path, GbkToUTF8(output))
	return nil
}

func ExecuteScript(scriptPath string, timeout ...time.Duration) ([]byte, error) {
	// 默认超时 5 秒
	duration := 5 * time.Second
	if len(timeout) > 0 {
		duration = timeout[0]
	}

	ctx, cancel := context.WithTimeout(context.Background(), duration)
	defer cancel()

	var cmd *exec.Cmd
	if runtime.GOOS == "windows" {
		// Windows: 用 cmd.exe 执行 .bat，并显示窗口
		cmd = exec.CommandContext(ctx, "cmd", "/C", scriptPath)
		// 关键：设置 SysProcAttr 以显示命令行窗口
		cmd.SysProcAttr = &syscall.SysProcAttr{
			HideWindow: false, // false 表示显示窗口（默认 true 为隐藏）
		}
	} else {
		// Linux/macOS: 用 sh 执行 .sh 脚本
		cmd = exec.CommandContext(ctx, "/bin/sh", scriptPath)
	}
	cmd.Dir = "." // 默认当前目录

	// 执行并捕获输出
	output, err := cmd.CombinedOutput()
	if ctx.Err() == context.DeadlineExceeded {
		return nil, fmt.Errorf("脚本执行超时 (%v)", duration)
	}
	if err != nil {
		// 如果是退出错误，包含退出码
		if exitErr, ok := err.(*exec.ExitError); ok {
			return output, fmt.Errorf("脚本执行失败 (退出码: %d): %w", exitErr.ExitCode(), err)
		}
		return nil, fmt.Errorf("脚本执行失败: %w", err)
	}
	return output, nil
}
